#include "autostatus.h"

ConfigRule *config_rules_new()
{
    ConfigRule *rule = (ConfigRule *) calloc(1, sizeof(ConfigRule));
    rule->name = NULL;
    rule->netid = NULL;
    rule->uuid = NULL;
}

void config_rules_free(ConfigRule *rule)
{
    if (rule == NULL) return;
    ConfigRule *tmp;
    do
    {
        tmp = rule->next; 
        if (rule->name)
            g_free(rule->name);
        if (rule->netid)
            g_free(rule->netid);
        if (rule->uuid)
            g_free(rule->uuid);
        g_free(rule);
        rule = tmp;
    }while(rule != NULL);
}

GtkWidget *saved_rules_list_new()
{
	GtkWidget *treeview;
	GtkTreeSelection *sel;
	GtkTreeViewColumn *column;
	GtkCellRenderer *renderer;
	

	/* Create the list model */
	GtkTreeModel *model = gtk_list_store_new(SAVED_CFG_COLUMNS,
									   G_TYPE_STRING,
                                       G_TYPE_POINTER);

	/* Create the treeview */
	treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));

	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
	//g_signal_connect(G_OBJECT(treeview), "row-activated",
    //						G_CALLBACK(savedstatus_activated_cb), dialog);

	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
	gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE);
	//g_signal_connect(G_OBJECT(sel), "changed",
    //					 G_CALLBACK(status_selected_cb), dialog);


	/* Add columns */
	column = gtk_tree_view_column_new();
	gtk_tree_view_column_set_title(column, "Saved rules");
	//gtk_tree_view_column_set_resizable(column, TRUE);
	gtk_tree_view_column_set_min_width(column, 100);
	//gtk_tree_view_column_set_sort_column_id(column,
	//										STATUS_WINDOW_COLUMN_TITLE);
	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
	renderer = gtk_cell_renderer_text_new();
	gtk_tree_view_column_pack_start(column, renderer, TRUE);
	gtk_tree_view_column_add_attribute(column, renderer, "text",
									   SAVED_CFG_RULE );
	g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);

	return treeview;
}

GtkWidget *saved_network_rules_list_new(ConfigWindow *dialog)
{
	GtkWidget *sw;
    /* Create the scrolled window */
	sw = gtk_scrolled_window_new(0, 0);

	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
								   GTK_POLICY_AUTOMATIC,
								   GTK_POLICY_ALWAYS);
	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
										GTK_SHADOW_IN);

    GtkWidget *treeview = saved_rules_list_new();

	gtk_container_add(GTK_CONTAINER(sw), treeview);

    GtkTreeModel *model = gtk_tree_view_get_model(treeview);

	dialog->saved_network_rules_list = treeview;

    ConfigRule *_rule_tmp = dialog->plugin->rules; 
    GtkTreeIter iter;

    if (_rule_tmp == NULL)
        DEBUG("saved rules is NULL");  

    while(_rule_tmp != NULL)
    {
        DEBUG("saved network rules find:%s", _rule_tmp->name);
        if (_rule_tmp->rule_type != RULE_TYPE_NETWORK)
        {
            _rule_tmp = _rule_tmp->next;
            continue;
        }
        gtk_list_store_append (model, &iter);
        gtk_list_store_set (model, &iter,
                        SAVED_CFG_RULE, _rule_tmp->name,
                        SAVED_CFG_DATA, (gpointer)_rule_tmp,
                        -1); 
        _rule_tmp = _rule_tmp->next;
    }
    
	gtk_widget_show_all(sw);
    return sw;
}


GtkWidget *saved_time_rules_list_new(ConfigWindow *dialog)
{
	GtkWidget *sw;
    /* Create the scrolled window */
	sw = gtk_scrolled_window_new(0, 0);

	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
								   GTK_POLICY_AUTOMATIC,
								   GTK_POLICY_ALWAYS);
	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
										GTK_SHADOW_IN);

    GtkWidget *treeview = saved_rules_list_new();

	gtk_container_add(GTK_CONTAINER(sw), treeview);

    GtkTreeModel *model = gtk_tree_view_get_model(treeview);

	dialog->saved_time_rules_list = treeview;

    ConfigRule *_rule_tmp = dialog->plugin->rules; 
    GtkTreeIter iter;

    if (_rule_tmp == NULL)
        DEBUG("saved rules is NULL");  

    while(_rule_tmp != NULL)
    {
        DEBUG("saved time rules find:%s", _rule_tmp->name);

        if (_rule_tmp->rule_type != RULE_TYPE_TIME)
        {
            _rule_tmp = _rule_tmp->next;
            continue;
        }

        gtk_list_store_append (model, &iter);
        gtk_list_store_set (model, &iter,
                        SAVED_CFG_RULE, _rule_tmp->name,
                        SAVED_CFG_DATA, (gpointer)_rule_tmp,
                        -1); 
        _rule_tmp = _rule_tmp->next;
    }
    
	gtk_widget_show_all(sw);
    return sw;
}

void load_rules(AutoStatus *plg)
{
    DEBUG("load_rules start");

    GList *rules = purple_prefs_get_string_list(PREF_CFG_SAVED_RULE); 
    if (rules == NULL)
    {
        DEBUG("no saved rules find");
        plg->rules = NULL; 
        return;
    }
    GList *rule_start = g_list_first(rules);
    ConfigRule *rule_sts = NULL;
    
    if (rule_start == NULL) 
        DEBUG("no saved rules find...");
    while(rule_start != NULL)
    {
        DEBUG("saved rules find");
        char *rule_str = (char *)rule_start->data;
        DEBUG("rule string:%s", rule_str);

        char *rule_str_pos = rule_str;
        char *rule_str_last_pos = rule_str;
        ConfigRule *rule_tmp = config_rules_new(); 
        int get_vnum = 0; 
        char *decode_buf;
        int decode_len;
        int str_end = 0;

        while(1)
        {
            if (*rule_str_pos == '@' || *rule_str_pos == '\0') 
            {
                if (*rule_str_pos == '\0')
                    str_end = 1;
                else
                    *rule_str_pos = '\0';

		DEBUG("get_vnum:%d", get_vnum);
                switch(get_vnum)
                {
                    case 0:
                        rule_tmp->rule_type = atoi(rule_str_last_pos);
                        DEBUG("rule type:%d", rule_tmp->rule_type);
                        break;
                    case 1:
			DEBUG("get rule name");
			rule_tmp->name = strdup(rule_str_last_pos);
                        break;
                    case 2:
                        rule_tmp->status_type = atoi(rule_str_last_pos); 
			DEBUG("status type:%d", rule_tmp->status_type);
                        break;
                    case 3:
                        rule_tmp->status_key = atoi(rule_str_last_pos); 
			DEBUG("status key:%d", rule_tmp->status_key);
                        break;
                    case 4:
                        if (rule_str_last_pos != '\0')
                        {
                            rule_tmp->uuid = strdup(rule_str_last_pos);
                        	DEBUG("rule uuid:%s", rule_tmp->uuid);
                        }
                        break;
                    case 5:
                        if (rule_str_last_pos != '\0')
                        {
                            rule_tmp->time_seconds = atoi(rule_str_last_pos);
                        }
                        break;
                    case 6:
                        if (rule_str_last_pos != '\0')
                        {
                            rule_tmp->time_interval = atoi(rule_str_last_pos);
                        }
                        break;

                }
                get_vnum ++;
                rule_str_last_pos = rule_str_pos + 1;
            }

            if (str_end)
                break;

            rule_str_pos ++;
        }
        
        DEBUG("append a saved rule");

	decode_buf = g_base64_decode(rule_tmp->name, &decode_len);
	free(rule_tmp->name);
	rule_tmp->name = strndup(decode_buf, decode_len);
	DEBUG("rule name:%s", rule_tmp->name);
	g_free(decode_buf);

        if (rule_sts == NULL)
            rule_sts = rule_tmp;
        else
        {
            ConfigRule *_rtmp = rule_sts; 
            while(_rtmp->next != NULL)
                _rtmp = _rtmp->next;
            _rtmp->next = rule_tmp;
        }

        rule_start = rule_start->next;
    }
    
    g_list_foreach (rules, (GFunc)g_free, NULL);
    g_list_free(rules);
    
    plg->rules = rule_sts;
    if (plg->rules == NULL)
        DEBUG("no saved rules find~");
    DEBUG("load_rules end");
}

void save_rules(AutoStatus *plg)
{
    DEBUG("save rules start");
    if (plg->rules == NULL) return;
    ConfigRule *tmp = plg->rules;
    GList *rules = NULL;

    while(tmp != NULL)
    {
        char *str_rule;
        gchar *name = g_base64_encode(tmp->name, strlen(tmp->name));
        if (tmp->rule_type == RULE_TYPE_NETWORK)
        {
            str_rule = (char *)malloc(sizeof(tmp->rule_type) + strlen(name) + strlen(tmp->uuid) + 20);
            sprintf(str_rule, "%d@%s@%d@%d@%s@@", tmp->rule_type, name, tmp->status_type, tmp->status_key, tmp->uuid);
        }
        else if (tmp->rule_type == RULE_TYPE_TIME)
        {
            str_rule = (char *)malloc(sizeof(tmp->rule_type) + strlen(name) + sizeof(tmp->time_seconds) + sizeof(tmp->time_interval) + 20);
            sprintf(str_rule, "%d@%s@%d@%d@@%d@%d", tmp->rule_type, name, tmp->status_type, tmp->status_key, tmp->time_seconds, tmp->time_interval);
        }

        g_free(name);
        rules = g_list_append(rules, str_rule);
        tmp = tmp->next;
    }

    purple_prefs_set_string_list(PREF_CFG_SAVED_RULE, rules);
    g_list_foreach (rules, (GFunc)g_free, NULL);
    g_list_free(rules);
    DEBUG("save rules end");
}

int delete_rule(AutoStatus *plg, ConfigRule *rule)
{
    ConfigRule *_rule_tmp = plg->rules;
    ConfigRule *_rule_tmp2 = plg->rules;
    if (rule == NULL) return -1;

    if (_rule_tmp == rule)
    {
        plg->rules = _rule_tmp->next;
        _rule_tmp->next = NULL;
        config_rules_free(_rule_tmp);
        save_rules(plg);
        return 0; 
    }

    while(_rule_tmp != NULL)
    {
        if (_rule_tmp == rule) 
        {
            while(_rule_tmp2->next != NULL && _rule_tmp2->next != rule)      
                _rule_tmp2 = _rule_tmp2->next;
            _rule_tmp2->next = rule->next; 
            rule->next = NULL;
            config_rules_free(rule);
            save_rules(plg);
            return 0;
        }
        _rule_tmp = _rule_tmp->next;
    }

    return -1;
}

ConfigRule *add_network_rule(AutoStatus *plg, char *status_title, int status_type, int status_key, char *netid, char *uuid)
{
    DEBUG("add_networ_rule start");

    ConfigRule *_tmp = plg->rules;

    while(_tmp != NULL)
    {
        if (_tmp->status_type == status_type && _tmp->status_key == status_key && strcmp(_tmp->uuid, uuid ) == 0) 
            return NULL;
        _tmp = _tmp->next;
    }

    ConfigRule *rule = config_rules_new(); 

    if (plg->rules == NULL)
        plg->rules = rule;
    else
    {
        _tmp = plg->rules;
        while(_tmp->next != NULL)
            _tmp = _tmp->next;
        _tmp->next = rule;
    }

    rule->name = (char *)malloc(strlen(status_title) + strlen(netid) + 100);
    sprintf(rule->name, "change to '%s' when '%s' connected", status_title, netid);
    rule->uuid = strdup(uuid);
    rule->netid = strdup(netid); 
    rule->status_type = status_type; 
    rule->status_key = status_key;
    rule->rule_type = RULE_TYPE_NETWORK;
    
    DEBUG("add_network_rule end");
    return rule;
}

ConfigRule *add_time_rule(AutoStatus *plg, char *status_title, int status_type, int status_key, char *time_string, int time_interval)
{
    DEBUG("add_time_rule start");
    ConfigRule *_tmp = plg->rules;
    char *interval_tip[5]; 

    interval_tip[TIME_INTERVAL_EVERYDAY] = "day";
    interval_tip[TIME_INTERVAL_WORKDAY] = "work day";
    interval_tip[TIME_INTERVAL_WEEKEND] = "weekend";

    int time_seconds;

    int time_hour, time_min;
    sscanf(time_string, "%d:%d", &time_hour, &time_min);

    GDateTime *now = g_date_time_new_now_local();    
    GDateTime *start =  g_date_time_new_local(
            g_date_time_get_year(now),
            g_date_time_get_month(now),
            g_date_time_get_day_of_month(now),
            0,
            0,
            0);

    GDateTime *end = g_date_time_new_local(
            g_date_time_get_year(now),
            g_date_time_get_month(now),
            g_date_time_get_day_of_month(now),
            time_hour,
            time_min,
            0);
    
    time_seconds = g_date_time_to_unix(end) - g_date_time_to_unix(start);

    g_date_time_unref(now);
    g_date_time_unref(start);
    g_date_time_unref(end);
    
    DEBUG("time seconds:%d", time_seconds);

    while(_tmp != NULL)
    {
        if (_tmp->time_seconds == time_seconds && _tmp->time_interval == time_interval) 
            return NULL;
        _tmp = _tmp->next;
    }

    ConfigRule *rule = config_rules_new(); 

    if (plg->rules == NULL)
        plg->rules = rule;
    else
    {
        _tmp = plg->rules;
        while(_tmp->next != NULL)
            _tmp = _tmp->next;
        _tmp->next = rule;
    }

    rule->name = (char *)malloc(strlen(status_title) + 100);
    sprintf(rule->name, "change to '%s' on '%s' every %s", status_title, time_string, interval_tip[time_interval]);
    rule->time_seconds = time_seconds;
    rule->time_interval = time_interval; 
    rule->status_type = status_type; 
    rule->status_key = status_key; 
    rule->rule_type = RULE_TYPE_TIME;
    
    DEBUG("add_time_rule end");
    return rule;
}

PurpleSavedStatus *get_saved_status(int status_type, int status_key)
{
    PurpleSavedStatus *status;
    if (status_type == SS_MENU_ENTRY_TYPE_PRIMITIVE)
	{
		status = purple_savedstatus_find_transient_by_type_and_message(status_key, NULL);
		if (status == NULL)
			status = purple_savedstatus_new(NULL, status_key);
	}
	else if (status_type == SS_MENU_ENTRY_TYPE_SAVEDSTATUS)
		status = purple_savedstatus_find_by_creation_time(status_key);
    return status;
}
